package au.com.handsunited.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.security.userdetails.UserDetails;

import au.com.handsunited.dao.EntityDAO;
import au.com.handsunited.dao.InvitationDAO;
import au.com.handsunited.dao.MessageDAO;
import au.com.handsunited.dao.UserDAO;
import au.com.handsunited.exception.business.UsernameExistsException;
import au.com.handsunited.exception.business.UsernameNotFoundException;
import au.com.handsunited.model.User;
import au.com.handsunited.model.invitations.Invitation;
import au.com.handsunited.model.relationship.RelationshipStatus;
import au.com.handsunited.model.relationship.Role;
import au.com.handsunited.model.skill.Skill;
import au.com.handsunited.model.validators.EmailAddressValidator;
import au.com.handsunited.service.UserService;
import au.com.handsunited.utils.Encrypter;


/**
 *
 * @author Arun Chandrasekhar
 * @date 21/12/2006 12:06:39 PM
 */
public class UserServiceImpl extends EntityServiceImpl implements UserService {

	private UserDAO userDAO;

	private static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);


	/**
	 *
	 *
	 */
	public UserServiceImpl() {
	}

	/**
	 *
	 * @param messageDAO
	 * @param userDAO
	 */
	public UserServiceImpl(EntityDAO entityDAO, MessageDAO messageDAO, InvitationDAO invitationDAO, UserDAO userDAO) {
		super(entityDAO, messageDAO, invitationDAO);
		this.userDAO = userDAO;
	}



	/**
	 * @throws UsernameExistsException
	 * @see au.com.handsunited.service.UserService#createUser(au.com.handsunited.model.old.User)
	 */
	public User createUser(User user) throws UsernameExistsException {

		if (findUserByUsername(user.getUsername()) != null) {
			throw new UsernameExistsException("Username[" + user.getUsername() + "] exists.");
		}

		//	Encrypt the password
		String plainTextPassword = user.getPassword();
		user.setPassword(Encrypter.sha(plainTextPassword));

		User newUser = (User) createEntity(user, null);

		if (UserServiceImpl.logger.isDebugEnabled()) {
			UserServiceImpl.logger.debug("New user account created for {}", newUser.getName());
		}

		return newUser;
	}


	/**
	 * @see au.com.handsunited.service.UserService#disableUser(java.lang.String)
	 */
	public boolean disableUser(String userId) {

		User user = getUser(userId);

		if (user.isActive()) {

			user.disable();
			user = userDAO.updateUser(user);

			if (UserServiceImpl.logger.isDebugEnabled()) {
				UserServiceImpl.logger.debug("User [{}] disabled.", user.getName());
			}
			return true;

		} else {

			if (UserServiceImpl.logger.isDebugEnabled()) {
				UserServiceImpl.logger.debug("Trying to disable an already disabled user [{}]", user.getName());
			}

			return false;
		}
	}


	/**
	 * @see au.com.handsunited.service.UserService#getUser(java.lang.String)
	 */
	public User getUser(String id) {

		return getUser(Long.parseLong(id));
	}


	/**
	 * @see au.com.handsunited.service.UserService#getUser(java.lang.Long)
	 */
	@Override
	public User getUser(Long id) {

		User user = (User) getEntity(id);

		if (user == null) {
			if (UserServiceImpl.logger.isWarnEnabled()) {
				UserServiceImpl.logger.warn("UserId[{}] not found in the database", id);
			}
		}
		return user;

	}


	/**
	 * @see au.com.handsunited.service.UserService#getAllUsers()
	 */
	@Override
	public List<User> getAllUsers() {

		List<User> users = userDAO.getUsers();
		return users;
	}

	/**
	 * @see au.com.handsunited.service.UserService#getAllUsersPaginated(int, int)
	 */
	public List<User> getAllUsersPaginated(int firstResult, int maxResults) {

		List<User> users = userDAO.getUsersPaginated(firstResult, maxResults);
		return users;
	}


	/**
	 * @see au.com.handsunited.service.UserService#findUserByUsername(java.lang.String)
	 */
	public User findUserByUsername(String username) {

		User user = userDAO.findUserByUsername(username);

		if (user == null) {
			if (UserServiceImpl.logger.isDebugEnabled()) {
				UserServiceImpl.logger.debug("Could not find user with username[{}].", username);
			}
		}

		return user;
	}


	/**
	 * @see au.com.handsunited.service.UserService#searchUsers(java.lang.String, java.lang.String, java.lang.String)
	 */
	public List<User> searchUsers(String firstName, String lastName, String emailAddress) {

		List<User> users = userDAO.searchActiveUsers(firstName, lastName, emailAddress);

		if (UserServiceImpl.logger.isDebugEnabled()) {
			UserServiceImpl.logger.debug("User Search [firstName={}, lastName={}, emailAddress={}] returned {} results",
					new String[] {firstName, lastName, emailAddress, users.size()+""});
		}

		return users;
	}

	/**
	 * @see au.com.handsunited.service.UserService#addUserToNetwork(au.com.handsunited.model.old.User, java.lang.String)
	 */
	public User addUserToNetwork(User user, String friendId) {

		User friend = getUser(friendId);

		addMemberToNetwork(user, friend, Role.OWNER, Role.OWNER, RelationshipStatus.AWAITING_AUTHORISATION, RelationshipStatus.ACTION_PENDING);

		return user;
	}

	/**
	 * @see au.com.handsunited.service.UserService#removeUserFromNetwork(au.com.handsunited.model.old.User, java.lang.String)
	 */
	public boolean removeUserFromNetwork(User user, String userIdToRemove) {

		if (UserServiceImpl.logger.isDebugEnabled()) {
			UserServiceImpl.logger.debug("Removing UserId[{}] from User[]'s user network.",
					new String[] {userIdToRemove, user.getName()});
		}
		return removeMemberFromNetwork(user, userIdToRemove);
	}


	/**
	 * @see au.com.handsunited.service.UserService#addUsersToNetwork(au.com.handsunited.model.User, java.util.List)
	 */
	public User addUsersToNetwork(User user, List<String> userIds) {

		for (String userId : userIds) {
			user = addUserToNetwork(user, userId);
		}

		return user;
	}

	/**
	 * @see au.com.handsunited.service.UserService#resetPassword(java.lang.String)
	 */
	@Override
	public User resetPassword(String username) throws UsernameNotFoundException {
		return null;
	}

	/**
	 * @see au.com.handsunited.service.UserService#updateUser(au.com.handsunited.model.User)
	 */
	@Override
	public User updateUser(User user) {

		return userDAO.updateUser(user);
	}

	/**
	 * @see au.com.handsunited.service.UserService#inviteUsers(User, java.lang.String, String)
	 */
	@Override
	public Map<String, List<Invitation>> inviteUsers(User user, String emailAddresses, String message) {

		Map<String, List<Invitation>> invitationsMap = new HashMap<String, List<Invitation>>();
		List<Invitation> validInvitations = new ArrayList<Invitation>();
		List<Invitation> invalidInvitations = new ArrayList<Invitation>();

		EmailAddressValidator emailAddressValidator = new EmailAddressValidator(emailAddresses);

		for (String emailAddress : emailAddressValidator.getValidEmailAddresses()) {
			validInvitations.add(invitePotentialEntity(user, emailAddress, Invitation.INVITEE_TYPE_USER, message));
		}

		invitationsMap.put(Invitation.VALID_EMAILADDRESSES, validInvitations);
		invitationsMap.put(Invitation.INVALID_EMAILADDRESSES, invalidInvitations);

		return invitationsMap;
	}


	/**
	 * @see au.com.handsunited.service.UserService#findUsersWithSkills(java.util.List, boolean)
	 */
	@Override
	public List<User> findUsersWithSkills(List<Skill> skills, boolean allSkillsRequired) {
		return userDAO.getUsers();
	}

	/**
	 * @see org.springframework.security.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
	 */
	@Override
	public UserDetails loadUserByUsername(String username)
			throws org.springframework.security.userdetails.UsernameNotFoundException,
			DataAccessException {

		User user = userDAO.findUserByUsername(username);

		if (user == null) {
			if (UserServiceImpl.logger.isDebugEnabled()) {
				UserServiceImpl.logger.debug("Could not find user with username[{}].", username);
			}
			throw new org.springframework.security.userdetails.UsernameNotFoundException("User [" + username + "] was not found");
		}

		return user;
	}

}
